﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Resources;
using System.Xml.Linq;
using QDP.Platform.IO;
using QDP.Platform.ObjService;
using QDP.Platform.Silverlight;
using QDP.Platform.Silverlight.Controls;
/// <summary>提供对开发者的支持。</summary>
public class D
{
    public static void Debug(string format, params object[] args)
    {
        string str = string.Format(format, args);
        System.Diagnostics.Debug.WriteLine("[" + DateTime.Now.ToString() + "]" + str);
    }
    const string LOAD_PART_SOURCE_IS_NULL = "LOAD_PART_SOURCE_IS_NULL";
    const string LOAD_PART_TYPE_UNDEFINE = "LOAD_PART_TYPE_UNDEFINE";
    const string LOAD_PART_XAP_FATAL = "LOAD_PART_XAP_FATAL";

    static D()
    {
        XapBuffer = new List<PackageObject>();
        var packageObject = new PackageObject { Key = string.Empty };
        packageObject.Buffer.Add(string.Empty, Assembly.GetExecutingAssembly());
        XapBuffer.Add(packageObject);
    }
    private static List<PackageObject> XapBuffer;

    #region 处理批量加载组件
    private static Action<LoadActionArgs> internalFreeBack;
    private static List<Widget> intrnalDownloadItems;
    /// <summary> 批量加载组件 </summary>
    /// <param name="items">需要加载的组件清单</param>
    /// <param name="FreeBack">加载状态发生变化时的用户反馈</param>
    /// <remarks></remarks>
    public static void LoadParts(List<Widget> items, Action<LoadActionArgs> FreeBack)
    {
        intrnalDownloadItems = items;
        internalFreeBack = FreeBack;
        InternalLoadParts();
    }
    /// <summary> [内部方法]用于递归数组，实现批量加载组件 </summary>
    private static void InternalLoadParts()
    {
        if (intrnalDownloadItems.Count == 0)
        {
            // 操作反馈：操作完成。
            internalFreeBack(new LoadActionArgs()
            {
                State = LoadActionState.Complated
            });
            return;
        }
        var entity = intrnalDownloadItems[0];

        // 操作反馈 ：开始下载
        internalFreeBack(new LoadActionArgs()
        {
            Navigation = entity.Navigation,
            State = LoadActionState.LoadBegin
        });

        LoadPart(entity, actionArgs =>
        {
            if (intrnalDownloadItems.Count > 0)
                intrnalDownloadItems.RemoveAt(0); // 移除已经下载的内容。
            actionArgs.State = LoadActionState.LoadComplated;
            internalFreeBack(actionArgs); // 操作反馈：单次下载完成
            InternalLoadParts();
        });
    }
    #endregion //#region 处理批量加载组件

    #region Version 2.0 加载方式
    public static void LoadXap(string url, Action<LoadActionArgs> FreeBack)
    {
        Load(url, FreeBack, LoadMode.Xap);
    }
    public static void LoadDll(string url, Action<LoadActionArgs> FreeBack)
    {
        Load(url, FreeBack, LoadMode.Dll);
    }
    /// <summary>加载包并解析至缓存区。</summary>
    /// <param name="url">包地址</param>
    /// <param name="FreeBack">操作反馈</param>
    private static void Load(string url, Action<LoadActionArgs> FreeBack, LoadMode Mode)
    {
        if (XapBuffer.Any(p => p.Key == url))
        {
            FreeBack(new LoadActionArgs() { State = LoadActionState.Complated });
        }
        else
        {
            Downloader downloader = new Downloader();
            downloader.DownloadCompleted += (s, e) =>
            {
                try
                {
                    if (Mode == LoadMode.Xap)
                        CreateXapPackage(url, e.MemoryStream);
                    else
                        CreateDllPackage(url, e.MemoryStream);
                    FreeBack(new LoadActionArgs() { State = LoadActionState.Complated });
                }
                catch (Exception ex)
                {
                    FreeBack(new LoadActionArgs()
                    {
                        State = LoadActionState.Error,
                        Error = ex
                    });
                }
            };
            downloader.ErrorAccured += (s, e) =>
            {
                FreeBack(new LoadActionArgs()
                {
                    State = LoadActionState.Error,
                    Error = e.Exception
                });
            };
            downloader.DownloadFile(url);
        }
    }
    private static void CreateDllPackage(string key, Stream stream)
    {
        PackageObject packageObject = null;
        if (XapBuffer.Any(p => p.Key == string.Empty))
        {
            packageObject = XapBuffer.First(p => p.Key == string.Empty);
        }
        else
        {
            packageObject = new PackageObject() { Key = string.Empty };
            XapBuffer.Add(packageObject);
        }

        if (packageObject.Buffer.ContainsKey(key) == false)
        {
            Assembly assembly = (new AssemblyPart()).Load(stream);
            packageObject.Buffer.Add(key, assembly);
        }
    }
    private static void CreateXapPackage(string key, Stream stream)
    {
        PackageObject packageObject = new PackageObject() { Key = key };

        var resource = Application.GetResourceStream(
                new StreamResourceInfo(stream, null),
                new Uri("AppManifest.xaml", UriKind.Relative));

        string resourceMainfest = new StreamReader(resource.Stream).ReadToEnd();
        var asmPartEls = XDocument.Parse(resourceMainfest)
           .Root
           .Elements()
           .First(p => p.Name.LocalName == "Deployment.Parts")
           .Elements();

        foreach (XElement asmPartEl in asmPartEls)
        {
            string source = asmPartEl.Attribute("Source").Value;

            var streamInfo = Application.GetResourceStream(
                    new StreamResourceInfo(stream, "application/binary"),
                    new Uri(source, UriKind.Relative));

            Assembly assembly = (new AssemblyPart()).Load(streamInfo.Stream);
            packageObject.Buffer.Add(source, assembly);
        }
        XapBuffer.Add(packageObject);
    }
    /// <summary>根据包地址获取包内程序集清单。</summary>
    /// <param name="url">包地址。</param>
    /// <returns>返回程序集清单。【string[]】</returns>
    public static string[] GetAssemblies(string url)
    {
        if (XapBuffer.Any(p => p.Key == url))
        {
            return XapBuffer.First(p => p.Key == url).Buffer.Keys.ToArray();
        }
        else
        {
            return new string[0];
        }
    }
    /// <summary>根据包地址和程序集名称获取程序集。</summary>
    /// <param name="url">包地址</param>
    /// <param name="name">程序集名称</param>
    /// <returns>返回程序集对象。</returns>
    public static Assembly GetAssembly(string url, string name)
    {
        var assemblies = GetAssemblies(url);
        if (assemblies.Contains(name))
        {
            return XapBuffer.First(p => p.Key == url).Buffer[name];
        }
        else
        {
            return null;
        }
    }
    #endregion //#region Version 2.0 加载方式

    /// <summary> 加载组件 </summary>
    /// <param name="Contract">组件描述文件</param>
    /// <param name="FreeBack">加载完成后的反馈</param>
    /// <remarks></remarks>
    public static void LoadPart(Widget Contract, Action<LoadActionArgs> FreeBack)
    {
        Debug("load:" + Contract.Navigation.Caption);
        if (Contract.PartElement != null)
        {
            // 操作反馈：返回组件
            FreeBack(new LoadActionArgs()
            {
                Error = null,
                Element = Contract.PartElement,
                Navigation = Contract.Navigation,
                State = LoadActionState.Complated
            });
            return;
        }
        var Navigation = Contract.Navigation as NavUISLXap;
        if (Navigation == null)
        {
            FreeBack(new LoadActionArgs()
               {
                   Error = new Exception("无法验证组件类型"),
                   Element = Contract.PartElement,
                   Navigation = Contract.Navigation,
                   State = LoadActionState.Error
               });
            return;
        }
        /**
          * 判断程序集库中是否含有请求的程序集
          * 若有则创建请求视图的示例，否则下载程序集。
          **/

        if (string.IsNullOrEmpty(Navigation.Source))
        {
            FreeBack(new LoadActionArgs()
            {
                Error = new Exception("组件源不能为空"),
                Navigation = Contract.Navigation,
                State = LoadActionState.Error
            });
            return;
        }

        /**
         * 校验组件装载类型
         * 若组件含有Package属性表示其需要通过xap文件装载
         * 否则视为通过dll即可装载。
         */
        bool isDll = string.IsNullOrEmpty(Navigation.Package);

        Load(isDll ? Navigation.Source : Navigation.Package, action =>
            {
                switch (action.State)
                {
                    case LoadActionState.Complated:
                        {
                            InstanceNavUISLXap(Contract, FreeBack);
                        }
                        break;
                    case LoadActionState.Error:
                        FreeBack(new LoadActionArgs()
                        {
                            Navigation = Contract.Navigation,
                            State = LoadActionState.Error,
                            Error = action.Error
                        });
                        break;
                }
            }, isDll ? LoadMode.Dll : LoadMode.Xap);
    }
    private static void InstanceNavUISLXap(Widget Contract, Action<LoadActionArgs> FreeBack)
    {
        var Navigation = Contract.Navigation as NavUISLXap;
        //if (Contract.Navigation.Caption == "待办事项")
        //{
        //}
        try
        {
            string package = Navigation.Package;
             // 获取库中已存在的程序集
            var assembly = GetAssembly(Navigation.Package, Navigation.Source);
            Type type = assembly.GetType(Navigation.Type);
            object instance = null;
            // 处理应用实例化传入参数
            if (Contract.Configs.ContainsKey(NParams.Args))
                instance = Activator.CreateInstance(type,Contract.Configs[NParams.Args]);
            else
                instance = Activator.CreateInstance(type);
            // 处理应用注册JavaScript对象
            if (Contract.Configs.ContainsKey(NParams.ScriptableObject))
                HtmlPage.RegisterScriptableObject(Contract.Configs[NParams.ScriptableObject], instance);
            // 实例化对象是IPartElement类型时，直接加入系统组件库。
            if (instance is PartElement)
            {
                #region 处理 IPartElement 类型组件
                var element = instance as PartElement;

                // 为组件传入配置信息；
                element.Config = Contract.Configs;
                element.Desc = Navigation;
                element.TileTemplate = Contract.TileTemplate;
                if (element.WidgetContent != null)
                {
                    element.WidgetContent.Tag = element.Config;
                }
                Contract.PartElement = element;
                FreeBack(new LoadActionArgs()
                {
                    Element = element,
                    Navigation = Navigation,
                    State = LoadActionState.Complated
                });
                #endregion //#region 处理 IPartElement 类型组件
            }
            // 实例化对象未实现IPartElement接口时，为其增加一个默认容器，用于装载组件.
            else if (instance is UserControl)
            {
                #region 处理 UserControl 类型组件
                var configInfo = Contract.Configs;
                var uc = instance as UserControl;
                //  uc.Name = Contract.Navigation.Code;
                var cfgs = Contract.Configs;
                uc.Tag = cfgs;
                uc.Name = "[" + Contract.Navigation.Code + "]" + DateTime.Now.ToString();
                var WidgetControl = new WidgetControl()
                {
                    Child = uc,
                    Widget = Contract
                };
                Contract.PartElement = new PartControl()
                {
                    WidgetContent = WidgetControl,
                    Desc = Navigation,
                    Config = Contract.Configs,
                    WidgetParent = Q.MainPage.ContentRoot,
                    TileTemplate = Contract.TileTemplate
                };
                FreeBack(new LoadActionArgs()
                {
                    Element = Contract.PartElement,
                    Navigation = Navigation,
                    State = LoadActionState.Complated
                });
                #endregion //#region 处理 UserControl 类型组件
            }
            else
            {
                #region 处理无法识别的类型组件
                FreeBack(new LoadActionArgs()
                {
                    Navigation = Navigation,
                    State = LoadActionState.Error,
                    Error = new Exception(string.Format(Q.ConfigManager.GetText(LOAD_PART_TYPE_UNDEFINE), Navigation.Code, Navigation.Caption))
                });
                #endregion //#region 处理无法识别的类型组件
            }
        }
        catch (Exception ex)
        {
            FreeBack(new LoadActionArgs()
            {
                Navigation = Navigation,
                State = LoadActionState.Error,
                Error = (ex.InnerException == null) ? ex : ex.InnerException
            });
        }
    }
    
    private class PackageObject
    {
        public PackageObject()
        {
            this.Buffer = new Dictionary<string, Assembly>();
        }
        public string Key { get; set; }
        public Dictionary<string, Assembly> Buffer { get; set; }
    }
    private enum LoadMode
    {
        Xap, Dll
    }
}

/// <summary>表示一个组件装载状态参数对象。</summary>
public class LoadActionArgs
{
    /// <summary>获取或设置装载组件的自描述信息。</summary>
    public NavigationBase Navigation { get; set; }
    /// <summary>获取或设置装载后组件实体对象。</summary>
    public PartElement Element { get; set; }
    /// <summary>获取或设置装载过程中的各阶段状态。</summary>
    public LoadActionState State { get; set; }
    /// <summary>获取或设置装载过程中出现的异常。</summary>
    public Exception Error { get; set; }
}
/// <summary>表示组件装载过程中各阶段的状态。</summary>
public enum LoadActionState
{
    /// <summary>表示开始加载清单</summary>
    Begin,
    /// <summary>表示开始加载组件</summary>
    LoadBegin,
    /// <summary>表示组件加载完成</summary>
    LoadComplated,
    /// <summary>表示组件清单加载完成</summary>
    Complated,
    /// <summary>表示装载过程中出现异常</summary>
    Error,
}